package services

import (
	"fmt"
	"github.com/beego/beego/v2/client/orm"
	"github.com/beego/beego/v2/server/web/context"
	"github.com/go-basic/uuid"
	"quickstart/models"
	"quickstart/utils"
	"strconv"
	"time"
)

type AuthService struct {
	User    models.User
	Token   string
	Logined bool
	error   string
}

func (as *AuthService) Init(token string) bool {
	if as.Logined {
		return true
	}
	if as.error != "" {
		return false
	}
	var ts TokenService
	tokenData := ts.GetToken(token)
	if tokenData == nil {
		return false
	}
	userId := tokenData.UserId
	if userId > 0 {
		o := orm.NewOrm()
		user := models.User{Id: userId}
		if err := o.Read(&user); err != nil {
			return false
		}
		as.User = user
		if user.Status != "normal" {
			return false
		}
		as.User = user
		as.Token = token
		as.Logined = true
	} else {
		return false
	}
	return true
}

//登录
func (as *AuthService) Login(username string, password string, ctx *context.Context) bool {
	o := orm.NewOrm()
	var user models.User
	err := o.QueryTable(user.TableName()).Filter("username", username).One(&user)
	if err != nil {
		return false
	}
	if err == orm.ErrNoRows {
		if as.Register(username, password, ctx) {
			return true
		} else {
			return false
		}
	}
	if user.Status != "normal" {
		return false
	}
	fmt.Println(as.getEncryptPassword(password, user.Salt))
	fmt.Println(user.Password)
	if user.Password != as.getEncryptPassword(password, user.Salt) {
		as.setError("密码错误")
		return false
	}
	as.direct(user.Id, ctx)
	return true
}

func (as *AuthService) Register(username string, password string, ctx *context.Context, args ...string) bool {
	if len(username) == 0 {
		return false
	}
	var userModel models.User
	if !userModel.GetByUsername(username) {
		as.setError("用户名已存在")
		return false
	}
	if !userModel.GetByNickname(username) {
		as.setError("昵称已存在")
		return false
	}

	if len(args) > 1 && !userModel.GetByMobile(args[0]) {
		as.setError("手机号已存在")
		return false
	}
	if len(args) > 2 && !userModel.GetByEmail(args[1]) {
		as.setError("邮箱已存在")
		return false
	}
	o := orm.NewOrm()
	user := models.User{}
	user.Loginip = ctx.Input.IP()
	user.Logintime = time.Now().Unix()
	user.Username = username
	user.Salt = utils.GetCode(8)
	user.Password = as.getEncryptPassword(password, user.Salt)
	if len(args) > 1 {
		user.Email = args[0]
	}
	if len(args) > 2 {
		user.Mobile = args[1]
	}
	user.Score = 0
	user.Nickname = username
	user.Avatar = ""
	user.Jointime = time.Now().Unix()
	user.Joinip = ctx.Input.IP()
	user.Logintime = time.Now().Unix()
	user.Loginip = ctx.Input.IP()
	user.Prevtime = time.Now().Unix()
	user.Status = "normal"

	id, err := o.Insert(&user)
	if err != nil {
		return false
	}
	userRead := models.User{Id: id}
	if err := o.Read(&userRead); err != nil {
		return false
	}
	as.User = userRead
	as.Token = uuid.New()
	var ts TokenService
	if !ts.Set(as.Token, id) {
		return false
	}
	as.setCookie(id, as.Token, ctx)
	return true
}

func (*AuthService) getEncryptPassword(password string, salt string) string {
	return utils.GetMd5String(utils.GetMd5String(password) + salt)
}

func (as *AuthService) direct(uid int64, ctx *context.Context) bool {
	o := orm.NewOrm()
	user := models.User{Id: uid}
	if err := o.Read(&user); err != nil {
		return false
	}

	ip := ctx.Input.IP()
	unixtime := time.Now().Unix()

	if user.Logintime < utils.Unixtime() {
		user.Successions = 1
		user.Maxsuccessions = 1
	}
	user.Prevtime = user.Logintime
	user.Loginip = ip
	user.Logintime = unixtime
	_, err := o.Update(&user)
	if err != nil {
		return false
	}
	as.User = user
	as.Token = uuid.New()
	var ts TokenService
	if !ts.Set(as.Token, uid) {
		return false
	}
	as.setCookie(uid, as.Token, ctx)
	return true
}

func (as *AuthService) Logout(ctx *context.Context) bool {
	if !as.Logined {
		return false
	}
	as.Logined = false
	var ts TokenService
	ts.Delete(ctx.GetCookie("token"))
	as.delCookie(ctx)
	return true
}

func (*AuthService) setCookie(id int64, token string, ctx *context.Context) {
	idTostring := strconv.FormatInt(id, 10)
	expire := 30 * 86400
	ctx.SetCookie("uid", idTostring, expire)
	ctx.SetCookie("token", token, expire)
}

func (*AuthService) delCookie(ctx *context.Context) {
	ctx.SetCookie("uid", "")
	ctx.SetCookie("token", "")
}

func (as *AuthService) setError(err string) {
	as.error = err
}

func (as *AuthService) GetError() string {
	return as.error
}
